#include "scope.h"
#include "scope_core1.h"

static void scope_cali_load_default(void)
{
    g_scope_cfg.cali_data.magic1 = SCOPE_CALI_MAGIC;
    g_scope_cfg.cali_data.magic2 = SCOPE_CALI_MAGIC;
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            g_scope_cfg.cali_data.ch[i].gnd[j] = 137;
        }
        g_scope_cfg.cali_data.ch[i].scale[0] = 8;
        g_scope_cfg.cali_data.ch[i].scale[1] = 31;
        g_scope_cfg.cali_data.ch[i].scale[2] = 142;
        g_scope_cfg.cali_data.ch[i].gnd_trigger[0] = 1100;
        g_scope_cfg.cali_data.ch[i].gnd_trigger[1] = 1100;
        g_scope_cfg.cali_data.ch[i].gnd_trigger[2] = 1100;
    }
}

static void scope_cali_data_show(void)
{
    for (int ch = 0; ch < 2; ch++) {
        for (int i = 0; i < 3; i++) {
            log_printf("ch[%d].gnd[%d]:%d\n", ch, i, g_scope_cfg.cali_data.ch[ch].gnd[i]);
            log_printf("ch[%d].gnd_trigger[%d]:%d\n", ch, i, g_scope_cfg.cali_data.ch[ch].gnd_trigger[i]);
            log_printf("ch[%d].scale[%d]:%d\n", ch, i, g_scope_cfg.cali_data.ch[ch].scale[i]);
        }
    }
}

void scope_cali_init(void)
{
    lfs_file_t *file = lfs_spiflash_open(SCOPE_CFG_FILE, LFS_O_RDONLY, true);

    if (file) {
        lfs_spiflash_read(file, &g_scope_cfg.cali_data, sizeof(g_scope_cfg.cali_data));
        lfs_spiflash_close(file);
        log_printf("Load cali succ\n");  
    } else {
        log_printf("Load cali fail\n");  
    }

    if ((g_scope_cfg.cali_data.magic1 != SCOPE_CALI_MAGIC) || 
        (g_scope_cfg.cali_data.magic2 != SCOPE_CALI_MAGIC)) {
        log_printf("Scope Cali Data Invalid\n");        
        scope_cali_load_default();
    }
    scope_cali_data_show();
    g_scope_cfg.time_div_us = 1000000.0 * SCOPE_DIV_POINT_NUM * 32 / g_scope_cfg.rate; 
}

static void scope_cali_do_cali_ch(int ch)
{
    log_printf("start calibration data ch%d\n", ch);
    log_printf("set ref to gnd\n");
    scope_hw_set_sample_rate(10000000);
    scope_trigger_set_mode("Normal");
    scope_snap_set_running(true);
    scope_hw_set_ch_coupling(ch, SCOPE_COUPLING_DC);
    for (int i = 0; i < 3; i++) {
        mcp4725_output_set_mv(0);
        busy_wait_us_32(1000 * 50);  
        scope_hw_set_ch_scale(ch, i);
        busy_wait_us_32(1000 * 50);    
        g_scope_cfg.cali_data.ch[ch].gnd[i] = scope_snap_buffer_get_adc_avg(ch, 100);
        log_printf("ch[%d].gnd[%d]:%d\n", ch, i, g_scope_cfg.cali_data.ch[ch].gnd[i]);
    }

    for (int i = 0; i < 3; i++) {
        int vol = 3300;

        scope_hw_set_ch_scale(ch, i);
        busy_wait_us_32(1000 * 50); 
        for (int cnt = 0; cnt < 10; cnt++) {
            mcp4725_output_set_mv(vol);
            busy_wait_us_32(1000 * 50);  
            int value = scope_snap_buffer_get_adc_avg(ch, 100);
            if (value < 250) {
                g_scope_cfg.cali_data.ch[ch].scale[i] = vol / (value - g_scope_cfg.cali_data.ch[ch].gnd[i]);
                log_printf("ch[%d].scale[%d]:%d when %dmV value:%d\n", ch, i, g_scope_cfg.cali_data.ch[ch].scale[i], vol, value);
                break;
            }
            vol = vol * 8 / 10;
        }   
    }
    scope_hw_auto_ch_scale();
    log_printf("ch[%d] cali done\n", ch);
    scope_core1_stop();
}

static void scope_cali_do_cali_ch0(void)
{
    scope_cali_do_cali_ch(0);
}

static void scope_cali_do_cali_ch1(void)
{
    scope_cali_do_cali_ch(1);
}

static int scope_cali_get_trigger_status(int ch)
{
    if (ch == 0) {
        return gpio_get(PIN_ADC_TRIG0);
    }
    return gpio_get(PIN_ADC_TRIG1);
}

static void scope_cali_do_cali_trigger(int ch)
{
    int trigger_gnd;

    log_printf("start calibration trigger ch%d\n", ch);
    log_printf("set ref to gnd\n");
 
    mcp4725_output_set_mv(0);
    for (int i = 0; i < 3; i++) {
        trigger_gnd = 1000;
        mcp4725_trigger_set_mv(trigger_gnd);
        busy_wait_us_32(1000 * 10);
        scope_hw_set_ch_scale(ch, i);

        for (int cnt = 0; cnt < 100; cnt++) {
            mcp4725_trigger_set_mv(trigger_gnd);
            busy_wait_us_32(1000 * 10);    
            if (scope_cali_get_trigger_status(ch) == 0) {
                trigger_gnd -= 10;
            } else {
                trigger_gnd += 10;
            }
        }
        g_scope_cfg.cali_data.ch[ch].gnd_trigger[i] = trigger_gnd;
        log_printf("ch[%d] gnd[%d]:%d\n", ch, i, trigger_gnd);
    }
    scope_hw_auto_ch_scale();
    log_printf("ch[%d] cali done\n", ch);

    scope_core1_stop();
}

static void scope_cali_do_cali_trigger0(void)
{
    scope_cali_do_cali_trigger(0);
}

static void scope_cali_do_cali_trigger1(void)
{
    scope_cali_do_cali_trigger(1);
}

static void scope_cali_proc_set_calibration(char *value)
{
    int ch = atoi(value);

    if (strcmp("0", value) == 0) {
        scope_core1_start(scope_cali_do_cali_ch0);
    } 
    if (strcmp("1", value) == 0) {
        scope_core1_start(scope_cali_do_cali_ch1);
    }
    if (strcmp("t0", value) == 0) {
        scope_core1_start(scope_cali_do_cali_trigger0);
    } 
    if (strcmp("t1", value) == 0) {
        scope_core1_start(scope_cali_do_cali_trigger1);
    }
}
HTTPD_CGI_PARAM_DEFINE("Cali", scope_cali_proc_set_calibration);

static void scope_cali_proc_save_calibration(char *value)
{
    lfs_file_t *file = lfs_spiflash_open(SCOPE_CFG_FILE, LFS_O_WRONLY | LFS_O_CREAT, true);

    lfs_spiflash_write(file, &g_scope_cfg.cali_data, sizeof(g_scope_cfg.cali_data));
    lfs_spiflash_close(file);
    log_printf("Save %s done\n", SCOPE_CFG_FILE);
}
HTTPD_CGI_PARAM_DEFINE("CaliSave", scope_cali_proc_save_calibration);

static void scope_cali_proc_restore_cali_data(char *value)
{
    scope_cali_load_default();
    log_printf("CaliDefault\n");
}
HTTPD_CGI_PARAM_DEFINE("CaliDefault", scope_cali_proc_restore_cali_data);

static void scope_cali_proc_show_cali_data(char *value)
{
    scope_cali_data_show();
    log_printf("CaliShow\n");
}
HTTPD_CGI_PARAM_DEFINE("CaliShow", scope_cali_proc_show_cali_data);
